﻿using Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using TinyCsvParser;
using TinyCsvParser.Mapping;
using TinyCsvParser.TypeConverter;

namespace CSVParserDemo
{
    public class Automobile
    {
        public string Make { get; set; }
        public string Model { get; set; }
        public AutomobileType Type { get; set; }
        public int Year { get; set; }
        public decimal Price { get; set; }
        public AutomobileComment Comment { get; set; }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.AppendLine();
            builder.AppendLine($"Make: {Make}");
            builder.AppendLine($"Model: {Model}");
            builder.AppendLine($"Type: {Type.ToString()}");
            builder.AppendLine($"Year: {Year}");
            builder.AppendLine($"Price: {Price}");
            builder.AppendLine($"Comment: {Comment?.Comment}");

            return builder.ToString();
        }
    }

    public class AutomobileComment
    {
        public string Comment { get; set; }
    }

    public enum AutomobileType
    {
        None,
        Car,
        Truck,
        Motorbike
    }

    public class CsvAutomobileMapping : CsvMapping<Automobile>
    {
        public CsvAutomobileMapping() : base()
        {
            MapProperty(0, x => x.Make);
            MapProperty(1, x => x.Model);
            MapProperty(2, x => x.Type, new EnumConverter<AutomobileType>());
            MapProperty(3, x => x.Year);
            MapProperty(4, x => x.Price);
            MapProperty(5, x => x.Comment, new AutomobileCommentTypeConverter());
        }
    }

    public class AutomobileCommentTypeConverter : ITypeConverter<AutomobileComment>
    {
        public Type TargetType => typeof(AutomobileComment);

        public bool TryConvert(string value, out AutomobileComment result)
        {
            result = new AutomobileComment
            {
                Comment = value
            };
            return true;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //CsvParserOptions csvParserOptions = new CsvParserOptions(true, ',');
            //var csvParser = new CsvParser<Automobile>(csvParserOptions, new CsvAutomobileMapping());
            //var records = csvParser.Parse(.ReadFromFile("sample.txt", Encoding.UTF8);

            //foreach (var r in records)
            //{
            //    if (r.IsValid)
            //    {
            //        Console.WriteLine(r.Result.ToString());
            //    }

            //}

            // to:
            // Console.WriteLine("Input text:");
            // var input = Console.ReadLine();
            // var body = Utils.ConvertToBytesFromDataBaseBinaryString(input);
            // var decompressBody = Utils.Decompress(body);
            // Console.WriteLine(decompressBody);
            // goto to;

            TestElementAtOrDefault();

            var input = string.Empty;
            while (input != "exit")
            {
                try
                {
                    Console.WriteLine("Input exit will shut down.");
                    Console.WriteLine("Input text:");
                    input = Console.ReadLine();
                    var body = Utils.ConvertToBytesFromDataBaseBinaryString(input);
                    var decompressBody = Utils.Decompress(body);
                    Console.WriteLine(decompressBody);
                }
                catch(Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }

        static void TestElementAtOrDefault()
        {
            var array = new List<string>() { "a", "b", "c", "d" };
            var lastIndex = array.FindIndex(f => f == "c");
            var last = array.ElementAtOrDefault(lastIndex - 1);

        }

        public static byte[] Compress(string input)
        {
            byte[] encoded = Encoding.Unicode.GetBytes(input);
            using (var result = new MemoryStream())
            {
                using (var compressionStream = new GZipStream(result, CompressionMode.Compress, true))
                {
                    compressionStream.Write(encoded, 0, encoded.Length);
                    compressionStream.Flush();
                }
                return result.ToArray();
            }
        }

        public static string Decompress(byte[] input)
        {
            using (var source = new MemoryStream(input))
            {
                byte[] block = new byte[1024];
                using (var decompressionStream = new GZipStream(source, CompressionMode.Decompress, true))
                {
                    using (var outBuffer = new MemoryStream())
                    {
                        while (true)
                        {
                            var bytesRead = decompressionStream.Read(block, 0, block.Length);
                            if (bytesRead <= 0)
                            {
                                break;
                            }
                            else
                            {
                                outBuffer.Write(block, 0, bytesRead);
                            }
                        }

                        return Encoding.Unicode.GetString(outBuffer.ToArray());
                    }
                }
            }
        }
    }
}
